home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 015 / bawk2a.arc / BAWKDO.C < prev    next >
Encoding:
C/C++ Source or Header  |  1986-07-27  |  12.6 KB  |  660 lines

  1. /*
  2.  * Bawk C actions interpreter
  3.  */
  4. #include <stdio.h>
  5. #include "bawk.h"
  6.  
  7. dopattern ( pat )
  8. char *pat;
  9. {     
  10.     Where = PATTERN;
  11.     Actptr = pat;
  12.     getoken();
  13.     expression();
  14.     return popint();
  15.     }
  16.  
  17. doaction ( act )
  18. char *act;
  19. {     
  20.     Where = ACTION;
  21.     Actptr = act;
  22.     getoken();
  23.     while ( Token!=T_EOF ) statement();
  24.     }
  25.  
  26. expression () { 
  27.     expr1();
  28.  
  29.     if ( Token==T_ASSIGN ) { 
  30.         getoken();
  31.         assignment( expression() );
  32.         }
  33.     }
  34.  
  35. expr1 () { 
  36.     int ival;
  37.  
  38.     expr2();
  39.     for ( ;; ) { 
  40.         if ( Token==T_LIOR ) { 
  41.             getoken();
  42.             ival = popint();
  43.             expr2();
  44.             pushint( popint() || ival );
  45.             }
  46.         else return;
  47.         }
  48.     }
  49.  
  50. expr2 () { 
  51.     int ival;
  52.  
  53.     expr3();
  54.     for ( ;; ) { 
  55.         if ( Token==T_LAND ) { 
  56.             getoken();
  57.             ival = popint();
  58.             expr3();
  59.             pushint( popint() && ival );
  60.             }
  61.         else return;
  62.         }
  63.     }
  64.  
  65. expr3 () { 
  66.     int ival;
  67.  
  68.     expr4();
  69.     for ( ;; ) { 
  70.         if ( Token==T_IOR ) { 
  71.             getoken();
  72.             ival = popint();
  73.             expr4();
  74.             pushint( popint() | ival );
  75.             }
  76.         else return;
  77.         }
  78.     }
  79.  
  80.  
  81. expr4 () { 
  82.     int ival;
  83.  
  84.     expr5();
  85.     for ( ;; ) { 
  86.         if ( Token==T_AND ) { 
  87.             getoken();
  88.             ival = popint();
  89.             expr5();
  90.             pushint( popint() & ival );
  91.             }
  92.         else return;
  93.         }
  94.     }
  95.  
  96. expr5 () { 
  97.     int ival;
  98.  
  99.     expr6();
  100.     for ( ;; ) { 
  101.         if ( Token==T_XOR ) { 
  102.             getoken();
  103.             ival = popint();
  104.             expr6();
  105.             pushint( popint() ^ ival );
  106.             }
  107.         else return;
  108.         }
  109.     }
  110.  
  111. expr6 () { 
  112.     int ival;
  113.  
  114.     expr7();
  115.     for ( ;; ) { 
  116.         if ( Token==T_EQ ) { 
  117.             getoken();
  118.             ival = popint();
  119.             expr7();
  120.             pushint( ival == popint() );
  121.             }
  122.         else if ( Token==T_NE ) { 
  123.             getoken();
  124.             ival = popint();
  125.             expr7();
  126.             pushint( ival != popint() );
  127.             }
  128.         else return;
  129.         }
  130.     }
  131.  
  132. expr7 () { 
  133.     int ival;
  134.  
  135.     expr8();
  136.     for ( ;; ) { 
  137.         if ( Token==T_LE ) { 
  138.             getoken();
  139.             ival = popint();
  140.             expr8();
  141.             pushint( ival <= popint() );
  142.             }
  143.         else if ( Token==T_GE ) { 
  144.             getoken();
  145.             ival = popint();
  146.             expr8();
  147.             pushint( ival >= popint() );
  148.             }
  149.         else if ( Token==T_LT ) { 
  150.             getoken();
  151.             ival = popint();
  152.             expr8();
  153.             pushint( ival < popint() );
  154.             }
  155.         else if ( Token==T_GT ) { 
  156.             getoken();
  157.             ival = popint();
  158.             expr8();
  159.             pushint( ival > popint() );
  160.             }
  161.         else return;
  162.         }
  163.     }
  164.  
  165. expr8 () { 
  166.     int ival;
  167.  
  168.     expr9();
  169.     for ( ;; ) { 
  170.         if ( Token==T_SHL ) { 
  171.             getoken();
  172.             ival = popint();
  173.             expr9();
  174.             pushint( ival << popint() );
  175.             }
  176.         else if ( Token==T_SHR ) { 
  177.             getoken();
  178.             ival = popint();
  179.             expr9();
  180.             pushint( ival >> popint() );
  181.             }
  182.         else return;
  183.         }
  184.     }
  185.  
  186. expr9 () { 
  187.     int ival;
  188.  
  189.     expr10();
  190.     for ( ;; ) { 
  191.         if ( Token==T_ADD ) { 
  192.             getoken();
  193.             ival = popint();
  194.             expr10();
  195.             pushint( ival + popint() );
  196.             }
  197.         else if ( Token==T_SUB ) { 
  198.             getoken();
  199.             ival = popint();
  200.             expr10();
  201.             pushint( ival - popint() );
  202.             }
  203.         else return;
  204.         }
  205.     }
  206.  
  207. expr10 () { 
  208.     int ival;
  209.  
  210.     primary();
  211.     for ( ;; ) { 
  212.         if ( Token==T_MUL ) { 
  213.             getoken();
  214.             ival = popint();
  215.             primary();
  216.             pushint( ival * popint() );
  217.             }
  218.         else if ( Token==T_DIV ) { 
  219.             getoken();
  220.             ival = popint();
  221.             primary();
  222.             pushint( ival /popint() );
  223.             }
  224.         else if ( Token==T_MOD ) { 
  225.             getoken();
  226.             ival = popint();
  227.             primary();
  228.             pushint( ival % popint() );
  229.             }
  230.         else return;
  231.         }
  232.     }
  233.  
  234. primary () { 
  235.     int index;
  236.     DATUM data;
  237.     VARIABLE *pvar;
  238.  
  239.     switch ( Token ) { 
  240.       case T_LPAREN:
  241. /*
  242.  * it's a parenthesized expression
  243.  */
  244.          getoken();
  245.            expression();
  246.            if ( Token!=T_RPAREN ) error( "missing ')'", ACT_ERROR );
  247.            getoken();
  248.            break;
  249.        case T_LNOT:
  250.            getoken();
  251.            primary();
  252.            pushint( ! popint() );
  253.            break;
  254.        case T_NOT:
  255.            getoken();
  256.            primary();
  257.            pushint( ~ popint() );
  258.            break;
  259.        case T_ADD:
  260.            getoken();
  261.            primary();
  262.            break;
  263.        case T_SUB:
  264.            getoken();
  265.            primary();
  266.            pushint( - popint() );
  267.            break;
  268.        case T_INCR:
  269.        case T_DECR:
  270.            preincdec();
  271.            break;
  272.        case T_MUL:
  273.            getoken();
  274.            primary();
  275. /*
  276.  * If item on stack is an LVALUE, do an extra level of
  277.  * indirection before changing it to an LVALUE.
  278.  */
  279.          if ( Stackptr->lvalue )
  280.                Stackptr->value.ptrptr = (char **) *Stackptr->value.ptrptr;
  281.            Stackptr->lvalue = 1;
  282.            --Stackptr->class;
  283.            break;
  284.        case T_AND:
  285.            getoken();
  286.            primary();
  287.            if ( Stackptr->lvalue ) Stackptr->lvalue = 0;
  288.            else error( "'&' operator needs an lvalue", ACT_ERROR );
  289.            break;
  290.        case T_CONSTANT:
  291.            pushint( Value.ival );
  292.            getoken();
  293.            break;
  294.        case T_REGEXP:
  295. /*
  296.  * It's a regular expression - parse it and compile it.
  297.  */
  298.            if ( Where == PATTERN ) { 
  299. /*
  300.  * We're processing a pattern right now - perform a
  301.  * match of the regular expression agains input line.
  302.  */
  303.                unparse( Fields, Fieldcount, Linebuf, Fieldsep );
  304.                pushint( match( Linebuf, Value.dptr ) );
  305.                }
  306.            else push( 1, ACTUAL, BYTE, &Value );
  307.            getoken();
  308.            break;
  309.        case T_NF:
  310.            pushint( Fieldcount );
  311.            getoken();
  312.            break;
  313.        case T_NR:
  314.            pushint( Recordcount );
  315.            getoken();
  316.            break;
  317.        case T_FS:
  318.            Fieldsep[1] = 0;
  319.            data.dptr = Fieldsep;
  320.            push( 0, LVALUE, BYTE, &data );
  321.            getoken();
  322.            break;
  323.        case T_RS:
  324.            Recordsep[1] = 0;
  325.            data.dptr = Recordsep;
  326.            push( 0, LVALUE, BYTE, &data );
  327.            getoken();
  328.            break;
  329.        case T_FILENAME:
  330.            data.dptr = Filename;
  331.            push( 1, ACTUAL, BYTE, &data );
  332.            getoken();
  333.            break;
  334.        case T_DOLLAR:
  335. /*
  336.  * It's a reference to one (or all) of the words in Linebuf.
  337.  */
  338.            getoken();
  339.            primary();
  340.            if (( index = popint() ) != 0) { 
  341.                if ( index > Fieldcount ) index = Fieldcount;
  342.                else if ( index < 1 ) index = 1;
  343.               data.dptr = Fields[ index-1 ];
  344.                }
  345.            else { 
  346. /*
  347.  * Reconstitute the line buffer in case any of the
  348.  * fields have been changed.
  349.  */
  350.                unparse( Fields, Fieldcount, Linebuf, Fieldsep );
  351.                data.dptr = Linebuf;
  352.                }
  353. /*
  354.  * $<expr>'s are treated the same as string constants:
  355.  */
  356.            push( 1, ACTUAL, BYTE, &data );
  357.            break;
  358.        case T_STRING:
  359.            push( 1, ACTUAL, BYTE, &Value );
  360.            getoken();
  361.            break;
  362.        case T_FUNCTION:
  363. /*
  364.  * Do a built-in function call
  365.  */
  366.            index = Value.ival;
  367.            getoken();
  368.            function( index );
  369.            break;
  370.        case T_VARIABLE:
  371.            pvar = (VARIABLE *) Value.dptr;
  372.            getoken();
  373. /*
  374.  * it's a plain variable. The way a variable is
  375.  * represented on the stack depends on its type:
  376.  *      lvalue class value.dptr
  377.  * vars:  1      0   address of var
  378.  * ptrs:  1      1   ptr to address of ptr
  379.  * array: 0      1   address of var
  380.  */
  381.            if ( pvar->vclass && !pvar->vlen )
  382. /* it's a pointer */
  383.              data.dptr = (char *) &pvar->vptr;
  384.            else
  385. /* an array or simple variable */
  386.                data.dptr = pvar->vptr;
  387. /*
  388.  * If it's an array it can't be used as an LVALUE.
  389.  */
  390.            push( pvar->vclass, !pvar->vlen, pvar->vsize, &data );
  391.            break;
  392.        case T_EOF:
  393.            break;
  394.        default:
  395.            syntaxerror();
  396.         }
  397. /*
  398.  * a "[" means it's an array reference
  399.  */
  400.     if ( Token==T_LBRACKET ) { 
  401.         getoken();
  402.         if ( ! Stackptr->class )
  403.             error( "'[]' needs an array or pointer", ACT_ERROR );
  404. /*
  405.  * compute the subscript
  406.  */
  407.         expression();
  408.         if ( Token!=T_RBRACKET ) error( "missing ']'", ACT_ERROR );
  409.         getoken();
  410.         index = popint();
  411. /*
  412.  * compute the offset (subscript times two for int arrays)
  413.  * and then the effective address.
  414.  */
  415.         index *= Stackptr->size;
  416.         if ( Stackptr->lvalue )
  417. /*
  418.  * It's a pointer - don't forget that the stack top item's value is the
  419.  * address of the pointer so we must do another level of indirection.
  420.  */
  421.             Stackptr->value.dptr = *Stackptr->value.ptrptr+index;
  422.         else
  423. /*
  424.  * It's a plain array - the stack top item's value is the address of the
  425.  * first element in the array.
  426.  */
  427.         Stackptr->value.dptr += index;
  428.  
  429. /*
  430.  * The stack top item now becomes an LVALUE, but we've reduced the
  431.  * indirection level.
  432.  */
  433.         Stackptr->lvalue = 1;
  434.         --Stackptr->class;
  435.         }
  436.  
  437.     if ( Token==T_INCR || Token==T_DECR ) postincdec();
  438.     }
  439.  
  440. preincdec () { 
  441. /*
  442.  * Pre increment/decrement
  443.  */
  444.     int incr;
  445.  
  446.     incr = Token==T_INCR ? 1 : -1;
  447.     getoken();
  448.     primary();
  449.     if ( Stackptr->lvalue ) { 
  450.         if ( Stackptr->class ) incr *= Stackptr->size;
  451.         *Stackptr->value.ptrptr += incr;
  452.         }
  453.     else error( "pre '++' or '--' needs an lvalue", ACT_ERROR );
  454.     }
  455.  
  456. postincdec () { 
  457. /*
  458.  * Post increment/decrement
  459.  */
  460.     char **pp;
  461.     int incr;
  462.  
  463.     incr = Token==T_INCR ? 1 : -1;
  464.     getoken();
  465.     if ( Stackptr->lvalue ) { 
  466.         if ( Stackptr->class ) { 
  467. /*
  468.  * It's a pointer - save its old value then increment/decrement the pointer.
  469.  * This makes the item on top of the stack look like an array, which means it
  470.  * can no longer be used as an LVALUE. This doesn't really hurt, since it
  471.  * doesn't make much sense to say:
  472.  *   char *cp;
  473.  *   cp++ = value;
  474.  */
  475.             pp = (char **) *Stackptr->value.ptrptr;
  476.             *Stackptr->value.ptrptr += incr * Stackptr->size;
  477.             Stackptr->value.ptrptr = pp;
  478.             }
  479.         else {     
  480. /*
  481.  * It's a simple variable - save its old value then increment/decrement the
  482.  * variable.  This makes the item on top of the stack look like a constant,
  483.  * which means it can no longer be used as an LVALUE.  Same reasoning as above.
  484.  */
  485.             if ( Stackptr->size == BYTE ) pp = (char **) *Stackptr->value.dptr;
  486.             else pp = (char **) *Stackptr->value.ptrptr;
  487.             *Stackptr->value.ptrptr += incr;
  488.             Stackptr->value.ival = (int) pp;
  489.             }
  490.         Stackptr->lvalue = 0;
  491.         }
  492.     else error( "post '++' or '--' needs an lvalue", ACT_ERROR );
  493.     }
  494.  
  495. statement () {
  496. /*
  497.  * Evaluate a statement
  498.  */
  499.     char *repeat, *body;
  500.  
  501.     switch ( Token ) { 
  502.        case T_EOF:
  503.            break;
  504.        case T_CHAR:
  505.        case T_INT:
  506.            declist();
  507.            break;
  508.        case T_LBRACE:
  509. /*
  510.  * parse a compound statement
  511.  */
  512.            getoken();
  513.            while ( !Saw_break && Token!=T_RBRACE ) statement();
  514.  
  515.            if ( Token==T_RBRACE ) getoken();
  516.            break;
  517.        case T_IF:
  518. /*
  519.  * parse an "if-else" statement
  520.  */
  521.            if ( getoken() != T_LPAREN ) syntaxerror();
  522.            getoken();
  523.            expression();
  524.            if ( Token!=T_RPAREN ) syntaxerror();
  525.            getoken();
  526.            if ( popint() ) { 
  527.                statement();
  528.                if ( Token==T_ELSE ) { 
  529.                    getoken();
  530.                    skipstatement();
  531.                    }
  532.                }
  533.            else {     
  534.                skipstatement();
  535.                if ( Token==T_ELSE ) { 
  536.                    getoken();
  537.                    statement();
  538.                    }
  539.                }
  540.            break;
  541.        case T_WHILE:
  542. /*
  543.  * parse a "while" statement
  544.  */
  545.            repeat = Actptr;
  546.            for ( ;; ) { 
  547.                if ( getoken() != T_LPAREN ) syntaxerror();
  548.  
  549.                getoken();
  550.                expression();
  551.                if ( Token!=T_RPAREN ) syntaxerror();
  552.  
  553.                if ( popint() ) { 
  554.                    body = Actptr;
  555.                    getoken();
  556.                    statement();
  557.                    if ( Saw_break ) { 
  558.                        Actptr = body;
  559.                        Saw_break = 0;
  560.                        break;
  561.                        }
  562.                    Actptr = repeat;
  563.                    }
  564.                else break;
  565.                }
  566.            getoken();
  567.            skipstatement();
  568.            break;
  569.        case T_BREAK:
  570. /*
  571.  * parse a "break" statement
  572.  */
  573.            getoken();
  574.            Saw_break = 1;
  575.            break;
  576.        case T_SEMICOLON:
  577.            break;
  578.        default:
  579.            expression();
  580.            popint();
  581.        }
  582.  
  583.     if ( Token==T_SEMICOLON ) getoken();
  584.     }
  585.  
  586. skipstatement () { 
  587. /*
  588.  * Skip a statement
  589.  */
  590.  
  591.     switch ( Token ) { 
  592.        case T_LBRACE:
  593. /*
  594.  * skip a compound statement
  595.  */
  596.            skip( T_LBRACE, T_RBRACE );
  597.            break;
  598.        case T_IF:
  599. /*
  600.  * skip an "if-else" statement
  601.  */
  602.            getoken(); /* skip 'if' */
  603.            skip( T_LPAREN, T_RPAREN );
  604.            skipstatement();
  605.            if ( Token==T_ELSE ) { 
  606.                getoken();                     /* skip 'else' */
  607.                skipstatement();
  608.                }
  609.            break;
  610.        case T_WHILE:
  611. /*
  612.  * skip a "while" statement
  613.  */
  614.            getoken();                       /* skip 'while' */
  615.            skip( T_LPAREN, T_RPAREN );
  616.            skipstatement();
  617.            break;
  618.        default:
  619. /*
  620.  * skip a one-liner
  621.  */
  622.            while (Token!=T_SEMICOLON && Token!=T_RBRACE && Token!=T_EOF)
  623.              getoken();
  624.            if ( Token==T_EOF ) error( "unexpected end", ACT_ERROR );
  625.            if ( Token==T_SEMICOLON ) getoken();
  626.         }
  627.     }
  628.  
  629. skip ( left, right )
  630. char left, right;
  631. {     
  632. /*
  633.  * Skip matched left and right delimiters and everything in between
  634.  */
  635.     int parity;
  636.     char *save, errmsg[ 80 ];
  637.  
  638.     parity = 1;
  639.     save = Actptr;
  640.     while ( getoken() != T_EOF ) { 
  641.         if ( Token == left ) { 
  642.             save = Actptr;
  643.             ++parity;
  644.             }
  645.         else if ( Token == right ) --parity;
  646.         if ( !parity ) { 
  647.             getoken();
  648.             return;
  649.             }
  650.         }
  651.     Actptr = save;
  652.  
  653.     sprintf( errmsg, "mismatched '%c' and '%c'", left, right );
  654.     error( errmsg, ACT_ERROR );
  655.     }
  656.  
  657. syntaxerror () { 
  658.     error( "syntax error", ACT_ERROR );
  659.     }
  660.